﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Numerics;
using System.Text;
using UtilZ.Dotnet.Ex.Model;

namespace UtilZ.Dotnet.Ex.Base
{
    /// <summary>
    /// 流扩展类
    /// </summary>
    public static partial class StreamEx
    {
        #region ReadBuffer

        private static int GetReadEleCount<T>(long dataLength, int count)
             where T : struct, IConvertible, IFormattable, IComparable<T>, IEquatable<T>
        {
            int eleSize = TypeEx.SizeOf<T>();
            long maxCount = dataLength / eleSize;
            if (count > 0 && count <= maxCount)
            {
                return count;
            }
            else
            {
                return (int)maxCount;
            }
        }
        private static void PrimitiveReadBuffer<T>(BinaryReader reader, long dataLength, TypeCode dataTypeCode,
            T[] destination, TypeCode destDataTypeCode, int startIndex, int endIndex, int readCount)
        {
            int index = startIndex;
            if (destDataTypeCode == dataTypeCode)
            {
                //直接读取,无需转换
                switch (dataTypeCode)
                {
                    case TypeCode.Char:
                        var charIBuffer = destination as char[];
                        reader.Read(charIBuffer, startIndex, readCount);
                        break;
                    case TypeCode.Byte:
                        var byteIBuffer = destination as byte[];
                        reader.Read(byteIBuffer, startIndex, readCount);
                        break;
                    case TypeCode.SByte:
                        var sByteIBuffer = destination as sbyte[];
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            sByteIBuffer[index] = reader.ReadSByte();
                            index++;
                        }
                        break;
                    case TypeCode.Int16:
                        var int16IBuffer = destination as Int16[];
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            int16IBuffer[index] = reader.ReadInt16();
                            index++;
                        }
                        break;
                    case TypeCode.UInt16:
                        var uInt16IBuffer = destination as UInt16[];
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            uInt16IBuffer[index] = reader.ReadUInt16();
                            index++;
                        }
                        break;
                    case TypeCode.Int32:
                        var int32IBuffer = destination as Int32[];
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            int32IBuffer[index] = reader.ReadInt32();
                            index++;
                        }
                        break;
                    case TypeCode.UInt32:
                        var uInt32IBuffer = destination as UInt32[];
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            uInt32IBuffer[index] = reader.ReadUInt32();
                            index++;
                        }
                        break;
                    case TypeCode.Int64:
                        var int64IBuffer = destination as Int64[];
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            int64IBuffer[index] = reader.ReadInt64();
                            index++;
                        }
                        break;
                    case TypeCode.UInt64:
                        var uInt64IBuffer = destination as UInt64[];
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            uInt64IBuffer[index] = reader.ReadUInt64();
                            index++;
                        }
                        break;
                    case TypeCode.Single:
                        var floatIBuffer = destination as float[];
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            floatIBuffer[index] = reader.ReadSingle();
                            index++;
                        }
                        break;
                    case TypeCode.Double:
                        var doubleIBuffer = destination as double[];
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            doubleIBuffer[index] = reader.ReadDouble();
                            index++;
                        }
                        break;
                    case TypeCode.Decimal:
                        var decimalIBuffer = destination as decimal[];
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            decimalIBuffer[index] = reader.ReadDecimal();
                            index++;
                        }
                        break;
                    default:
                        throw new NotImplementedException($"未实现的目标数据类型{dataTypeCode.ToString()}");
                }
            }
            else
            {
                //需要隐式转换
                switch (dataTypeCode)
                {
                    case TypeCode.Char:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            destination.SetValue(reader.ReadChar(), index++);
                        }
                        break;
                    case TypeCode.Byte:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            destination.SetValue(reader.ReadByte(), index++);
                        }
                        break;
                    case TypeCode.SByte:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            destination.SetValue(reader.ReadSByte(), index++);
                        }
                        break;
                    case TypeCode.Int16:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            destination.SetValue(reader.ReadInt16(), index++);
                            //switch (destDataTypeCode)
                            //{
                            //    case TypeCode.Char:
                            //    case TypeCode.Byte:
                            //    case TypeCode.SByte:
                            //    case TypeCode.UInt16:
                            //    case TypeCode.UInt32:
                            //    case TypeCode.UInt64:
                            //    default:
                            //        throw new InvalidOperationException();
                            //    case TypeCode.Int32:
                            //        break;
                            //    case TypeCode.Int64:
                            //        break;
                            //    case TypeCode.Single:
                            //        break;
                            //    case TypeCode.Double:
                            //        break;
                            //    case TypeCode.Decimal:
                            //        break;
                            //}
                        }
                        break;
                    case TypeCode.UInt16:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            destination.SetValue(reader.ReadUInt16(), index++);
                        }
                        break;
                    case TypeCode.Int32:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            destination.SetValue(reader.ReadInt32(), index++);
                        }
                        break;
                    case TypeCode.UInt32:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            destination.SetValue(reader.ReadUInt32(), index++);
                        }
                        break;
                    case TypeCode.Int64:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            destination.SetValue(reader.ReadInt64(), index++);
                        }
                        break;
                    case TypeCode.UInt64:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            destination.SetValue(reader.ReadUInt64(), index++);
                        }
                        break;
                    case TypeCode.Single:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            destination.SetValue(reader.ReadSingle(), index++);
                        }
                        break;
                    case TypeCode.Double:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            destination.SetValue(reader.ReadDouble(), index++);
                        }
                        break;
                    case TypeCode.Decimal:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            destination.SetValue(reader.ReadDecimal(), index++);
                        }
                        break;
                    default:
                        throw new NotImplementedException($"未实现的目标数据类型{dataTypeCode.ToString()}");
                }
            }
        }


        private static int PrimitiveReadBuffer<T>(BinaryReader reader, long dataLength, TypeCode dataTypeCode, T[] destination, int startIndex, int readCount)
            where T : struct, IConvertible, IFormattable, IComparable<T>, IEquatable<T>
        {
            int endIndex = EnumerableEx.CheckCollectionPartRangePara(destination.Length, ref startIndex, ref readCount);
            if (dataLength < 0)
            {
                dataLength = reader.BaseStream.Length - reader.BaseStream.Position;
            }

            readCount = GetReadEleCount<T>(dataLength, readCount);
            PrimitiveReadBuffer(reader, dataLength, dataTypeCode, destination, Type.GetTypeCode(typeof(T)), startIndex, endIndex, readCount);
            return readCount;
        }


        /// <summary>
        /// 从数组中的指定点开始，从流中读取指定的元素个数
        /// </summary>
        /// <param name="filePath">数据文件路径</param>
        /// <param name="dataTypeCode">原始数据类型</param>
        /// <param name="destination">将数据读入的缓冲区</param>
        /// <param name="startIndex">缓冲区中的起始点，在该处开始读入缓冲区.小于表示0从头开始</param>
        /// <param name="count">要读取的元素个数.小于0表示到读取到destination结尾</param>
        /// <param name="fileOffset">文件中读取数据起始位置</param>
        /// <returns>读入destination的元素个数。 如果可用的字节没有请求的那么多，此数可能小于所请求的元素个数；如果到达了流的末尾，此数可能为零</returns>
        public static int ReadBuffer<T>(string filePath, TypeCode dataTypeCode, T[] destination, int startIndex = -1, int count = -1, long fileOffset = -1)
             where T : struct, IConvertible, IFormattable, IComparable<T>, IEquatable<T>
        {
            using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                if (fileOffset > 0)
                {
                    fs.Seek(fileOffset, SeekOrigin.Begin);
                }

                var reader = new BinaryReader(fs);
                return PrimitiveReadBuffer<T>(reader, fs.Length - fs.Position, dataTypeCode, destination, startIndex, count);
            }
        }

        /// <summary>
        /// 从数组中的指定点开始，从流中读取指定的元素个数
        /// </summary>
        /// <param name="buffer">数据destination</param>
        /// <param name="bufferStartIndex">数据buffer中的起始索引</param>
        /// <param name="dataTypeCode">原始数据类型</param>
        /// <param name="destination">将数据读入的缓冲区</param>
        /// <param name="startIndex">缓冲区中的起始点，在该处开始读入缓冲区.小于表示0从头开始</param>
        /// <param name="count">要读取的元素个数.小于0表示到读取到destination结尾</param>
        /// <returns>读入destination的元素个数。 如果可用的字节没有请求的那么多，此数可能小于所请求的元素个数；如果到达了流的末尾，此数可能为零</returns>
        public static int ReadBuffer<T>(byte[] buffer, int bufferStartIndex, TypeCode dataTypeCode, T[] destination, int startIndex = -1, int count = -1)
             where T : struct, IConvertible, IFormattable, IComparable<T>, IEquatable<T>
        {
            using (var ms = new MemoryStream(buffer, bufferStartIndex, buffer.Length - bufferStartIndex))
            {
                var reader = new BinaryReader(ms);
                return PrimitiveReadBuffer<T>(reader, ms.Length, dataTypeCode, destination, startIndex, count);
            }
        }

        /// <summary>
        /// 从数组中的指定点开始，从流中读取指定的元素个数
        /// </summary>
        /// <param name="dataSpan">数据destination</param>
        /// <param name="dataTypeCode">原始数据类型</param>
        /// <param name="destination">将数据读入的缓冲区</param>
        /// <param name="startIndex">缓冲区中的起始点，在该处开始读入缓冲区.小于表示0从头开始</param>
        /// <param name="count">要读取的元素个数.小于0表示到读取到destination结尾</param>
        /// <returns>读入destination的元素个数。 如果可用的字节没有请求的那么多，此数可能小于所请求的元素个数；如果到达了流的末尾，此数可能为零</returns>
        public static int ReadBuffer<T>(ValueTypeFlexibleArray<byte> dataSpan, TypeCode dataTypeCode, T[] destination, int startIndex = -1, int count = -1)
             where T : struct, IConvertible, IFormattable, IComparable<T>, IEquatable<T>
        {
            using (var fs = dataSpan.CreateStream(FileAccess.Read))
            {
                var reader = new BinaryReader(fs);
                return PrimitiveReadBuffer<T>(reader, dataSpan.Length, dataTypeCode, destination, startIndex, count);
            }
        }

        /// <summary>
        /// 从数组中的指定点开始，从流中读取指定的元素个数
        /// </summary>
        /// <param name="bufferData">数据destination</param>
        /// <param name="dataTypeCode">原始数据类型</param>
        /// <param name="destination">将数据读入的缓冲区</param>
        /// <param name="startIndex">缓冲区中的起始点，在该处开始读入缓冲区.小于表示0从头开始</param>
        /// <param name="count">要读取的元素个数.小于0表示到读取到destination结尾</param>
        /// <returns>读入destination的元素个数。 如果可用的字节没有请求的那么多，此数可能小于所请求的元素个数；如果到达了流的末尾，此数可能为零</returns>
        public static int ReadBuffer<T>(DataSource bufferData, TypeCode dataTypeCode, T[] destination, int startIndex = -1, int count = -1)
             where T : struct, IConvertible, IFormattable, IComparable<T>, IEquatable<T>
        {
            if (bufferData.DataType == DataSourceType.BinaryReader)
            {
                return PrimitiveReadBuffer<T>(bufferData.Reader, bufferData.LongLength, dataTypeCode, destination, startIndex, count);
            }
            else
            {
                using (var reader = DataSourceReader.Create(bufferData))
                {
                    return PrimitiveReadBuffer<T>(reader, bufferData.LongLength, dataTypeCode, destination, startIndex, count);
                }
            }
        }

        /// <summary>
        /// 从数组中的指定点开始，从流中读取指定的元素个数
        /// </summary>
        /// <param name="stream">数据流</param>
        /// <param name="dataTypeCode">原始数据类型</param>
        /// <param name="destination">将数据读入的缓冲区</param>
        /// <param name="startIndex">缓冲区中的起始点，在该处开始读入缓冲区.小于表示0从头开始</param>
        /// <param name="count">要读取的元素个数.小于0表示到读取到destination结尾</param>
        /// <returns>读入destination的元素个数。 如果可用的字节没有请求的那么多，此数可能小于所请求的元素个数；如果到达了流的末尾，此数可能为零</returns>
        public static int ReadBuffer<T>(Stream stream, TypeCode dataTypeCode, T[] destination, int startIndex = -1, int count = -1)
             where T : struct, IConvertible, IFormattable, IComparable<T>, IEquatable<T>
        {
            var reader = new BinaryReader(stream);
            return PrimitiveReadBuffer<T>(reader, -1, dataTypeCode, destination, startIndex, count);
        }

        /// <summary>
        /// 从数组中的指定点开始，从流中读取指定的元素个数
        /// </summary>
        /// <param name="reader">BinaryReader</param>
        /// <param name="dataTypeCode">原始数据类型</param>
        /// <param name="destination">将数据读入的缓冲区</param>
        /// <param name="startIndex">缓冲区中的起始点，在该处开始读入缓冲区.小于表示0从头开始</param>
        /// <param name="count">要读取的元素个数.小于0表示到读取到destination结尾</param>
        /// <returns>读入destination的元素个数。 如果可用的字节没有请求的那么多，此数可能小于所请求的元素个数；如果到达了流的末尾，此数可能为零</returns>
        public static int ReadBuffer<T>(BinaryReader reader, TypeCode dataTypeCode, T[] destination, int startIndex = -1, int count = -1)
             where T : struct, IConvertible, IFormattable, IComparable<T>, IEquatable<T>
        {
            return PrimitiveReadBuffer<T>(reader, -1, dataTypeCode, destination, startIndex, count);
        }

        //------------------------------------------------------------------------------------------------------------------------------

        private static T[] PrimitiveReadBuffer<T>(BinaryReader reader, long dataLength, TypeCode dataTypeCode, int readCount)
            where T : struct, IConvertible, IFormattable, IComparable<T>, IEquatable<T>
        {
            if (dataLength < 0)
            {
                dataLength = reader.BaseStream.Length - reader.BaseStream.Position;
            }

            readCount = GetReadEleCount<T>(dataLength, readCount);
            T[] destination = new T[readCount];
            PrimitiveReadBuffer(reader, dataLength, dataTypeCode, destination, Type.GetTypeCode(typeof(T)), 0, destination.Length, readCount);
            return destination;
        }

        /// <summary>
        /// 从数组中的指定点开始，从流中读取指定的元素个数
        /// </summary>
        /// <param name="filePath">数据文件路径</param>
        /// <param name="dataTypeCode">原始数据类型</param>
        /// <param name="fileOffset">文件中读取数据起始位置</param>
        /// <param name="count">要读取的元素个数.小于0表示到读取到destination结尾</param>
        /// <returns>读入destination的元素个数。 如果可用的字节没有请求的那么多，此数可能小于所请求的元素个数；如果到达了流的末尾，此数可能为零</returns>
        public static T[] ReadBuffer<T>(string filePath, TypeCode dataTypeCode, long fileOffset = -1, int count = -1)
             where T : struct, IConvertible, IFormattable, IComparable<T>, IEquatable<T>
        {
            if (string.IsNullOrEmpty(filePath))
            {
                throw new ArgumentNullException(nameof(filePath));
            }

            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException("数据文件不存在", filePath);
            }

            using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                if (fileOffset > 0)
                {
                    fs.Seek(fileOffset, SeekOrigin.Begin);
                }

                var reader = new BinaryReader(fs);
                return PrimitiveReadBuffer<T>(reader, fs.Length - fs.Position, dataTypeCode, count);
            }
        }

        /// <summary>
        /// 从数组中的指定点开始，从流中读取指定的元素个数
        /// </summary>
        /// <param name="buffer">数据buffer</param>
        /// <param name="bufferStartIndex">数据buffer中的起始索引</param>
        /// <param name="dataTypeCode">原始数据类型</param>
        /// <param name="count">要读取的元素个数.小于0表示到读取到destination结尾</param>
        /// <returns>读入destination的元素个数。 如果可用的字节没有请求的那么多，此数可能小于所请求的元素个数；如果到达了流的末尾，此数可能为零</returns>
        public static T[] ReadBuffer<T>(byte[] buffer, int bufferStartIndex, TypeCode dataTypeCode, int count = -1)
             where T : struct, IConvertible, IFormattable, IComparable<T>, IEquatable<T>
        {
            if (buffer == null)
            {
                throw new ArgumentNullException(nameof(buffer));
            }

            using (var ms = new MemoryStream(buffer, bufferStartIndex, buffer.Length - bufferStartIndex))
            {
                var reader = new BinaryReader(ms);
                return PrimitiveReadBuffer<T>(reader, ms.Length, dataTypeCode, count);
            }
        }

        /// <summary>
        /// 从数组中的指定点开始，从流中读取指定的元素个数
        /// </summary>
        /// <param name="dataSpan">数据destination</param>
        /// <param name="dataTypeCode">原始数据类型</param>
        /// <param name="count">要读取的元素个数.小于0表示到读取到destination结尾</param>
        /// <returns>读入destination的元素个数。 如果可用的字节没有请求的那么多，此数可能小于所请求的元素个数；如果到达了流的末尾，此数可能为零</returns>
        public static T[] ReadBuffer<T>(ValueTypeFlexibleArray<byte> dataSpan, TypeCode dataTypeCode, int count = -1)
             where T : struct, IConvertible, IFormattable, IComparable<T>, IEquatable<T>
        {
            if (dataSpan == null)
            {
                throw new ArgumentNullException(nameof(dataSpan));
            }

            using (var fs = dataSpan.CreateStream(FileAccess.Read))
            {
                var reader = new BinaryReader(fs);
                return PrimitiveReadBuffer<T>(reader, dataSpan.Length, dataTypeCode, count);
            }
        }

        /// <summary>
        /// 从数组中的指定点开始，从流中读取指定的元素个数
        /// </summary>
        /// <param name="bufferData">数据destination</param>
        /// <param name="dataTypeCode">原始数据类型</param>
        /// <param name="count">要读取的元素个数.小于0表示到读取到destination结尾</param>
        /// <returns>读入destination的元素个数。 如果可用的字节没有请求的那么多，此数可能小于所请求的元素个数；如果到达了流的末尾，此数可能为零</returns>
        public static T[] ReadBuffer<T>(DataSource bufferData, TypeCode dataTypeCode, int count = -1)
             where T : struct, IConvertible, IFormattable, IComparable<T>, IEquatable<T>
        {
            if (bufferData == null)
            {
                throw new ArgumentNullException(nameof(bufferData));
            }

            if (bufferData.DataType == DataSourceType.BinaryReader)
            {
                return PrimitiveReadBuffer<T>(bufferData.Reader, bufferData.LongLength, dataTypeCode, count);
            }
            else
            {
                using (var reader = DataSourceReader.Create(bufferData))
                {
                    return PrimitiveReadBuffer<T>(reader, bufferData.LongLength, dataTypeCode, count);
                }
            }
        }

        /// <summary>
        /// 从数组中的指定点开始，从流中读取指定的元素个数
        /// </summary>
        /// <param name="stream">数据流</param>
        /// <param name="dataTypeCode">原始数据类型</param>
        /// <param name="count">要读取的元素个数.小于0表示到读取到destination结尾</param>
        /// <returns>读入destination的元素个数。 如果可用的字节没有请求的那么多，此数可能小于所请求的元素个数；如果到达了流的末尾，此数可能为零</returns>
        public static T[] ReadBuffer<T>(Stream stream, TypeCode dataTypeCode, int count = -1)
             where T : struct, IConvertible, IFormattable, IComparable<T>, IEquatable<T>
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            if (!stream.CanRead)
            {
                throw new ArgumentException("数据流不可读", nameof(stream));
            }

            var reader = new BinaryReader(stream);
            return PrimitiveReadBuffer<T>(reader, -1, dataTypeCode, count);
        }

        /// <summary>
        /// 从数组中的指定点开始，从流中读取指定的元素个数
        /// </summary>
        /// <param name="reader">BinaryReader</param>
        /// <param name="dataTypeCode">原始数据类型</param>
        /// <param name="count">要读取的元素个数.小于0表示到读取到destination结尾</param>
        /// <returns>读入destination的元素个数。 如果可用的字节没有请求的那么多，此数可能小于所请求的元素个数；如果到达了流的末尾，此数可能为零</returns>
        public static T[] ReadBuffer<T>(BinaryReader reader, TypeCode dataTypeCode, int count = -1)
             where T : struct, IConvertible, IFormattable, IComparable<T>, IEquatable<T>
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            if (!reader.BaseStream.CanRead)
            {
                throw new ArgumentException("数据流不可读", nameof(reader));
            }

            return PrimitiveReadBuffer<T>(reader, -1, dataTypeCode, count);
        }

        #endregion


        #region WriteBuffer

        private static void PrimitiveWriteBuffer<T>(BinaryWriter writer, TypeCode? dataTypeCode, T[] buffer, int startIndex, int writeCount)
        {
            int endIndex = EnumerableEx.CheckCollectionPartRangePara(buffer.Length, ref startIndex, ref writeCount);
            TypeCode bufferDataTypeCode = Type.GetTypeCode(typeof(T));
            if (!dataTypeCode.HasValue ||
                dataTypeCode.HasValue && dataTypeCode.Value == bufferDataTypeCode)
            {
                //直接写入,无需转换
                switch (bufferDataTypeCode)
                {
                    case TypeCode.Char:
                        var charIBuffer = buffer as char[];
                        writer.Write(charIBuffer, startIndex, writeCount);
                        break;
                    case TypeCode.Byte:
                        var byteIBuffer = buffer as byte[];
                        writer.Write(byteIBuffer, startIndex, writeCount);
                        break;
                    case TypeCode.SByte:
                        var sByteIBuffer = buffer as sbyte[];
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(sByteIBuffer[i]);
                        }
                        break;
                    case TypeCode.Int16:
                        var int16IBuffer = buffer as Int16[];
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(int16IBuffer[i]);
                        }
                        break;
                    case TypeCode.UInt16:
                        var uInt16IBuffer = buffer as UInt16[];
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(uInt16IBuffer[i]);
                        }
                        break;
                    case TypeCode.Int32:
                        var int32IBuffer = buffer as Int32[];
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(int32IBuffer[i]);
                        }
                        break;
                    case TypeCode.UInt32:
                        var uInt32IBuffer = buffer as UInt32[];
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(uInt32IBuffer[i]);
                        }
                        break;
                    case TypeCode.Int64:
                        var int64IBuffer = buffer as Int64[];
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(int64IBuffer[i]);
                        }
                        break;
                    case TypeCode.UInt64:
                        var uInt64IBuffer = buffer as UInt64[];
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(uInt64IBuffer[i]);
                        }
                        break;
                    case TypeCode.Single:
                        var floatIBuffer = buffer as float[];
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(floatIBuffer[i]);
                        }
                        break;
                    case TypeCode.Double:
                        var doubleIBuffer = buffer as double[];
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(doubleIBuffer[i]);
                        }
                        break;
                    case TypeCode.Decimal:
                        var decimalIBuffer = buffer as decimal[];
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(decimalIBuffer[i]);
                        }
                        break;
                    default:
                        throw new NotImplementedException($"未实现的目标数据类型{dataTypeCode.ToString()}");
                }
            }
            else
            {
                //需要转换后,再写入
                switch (dataTypeCode.Value)
                {
                    case TypeCode.Char:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(Convert.ToChar(buffer[i]));
                        }
                        break;
                    case TypeCode.Byte:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(Convert.ToByte(buffer[i]));
                        }
                        break;
                    case TypeCode.SByte:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(Convert.ToSByte(buffer[i]));
                        }
                        break;
                    case TypeCode.Int16:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(Convert.ToInt16(buffer[i]));
                        }
                        break;
                    case TypeCode.UInt16:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(Convert.ToUInt16(buffer[i]));
                        }
                        break;
                    case TypeCode.Int32:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(Convert.ToInt32(buffer[i]));
                        }
                        break;
                    case TypeCode.UInt32:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(Convert.ToUInt32(buffer[i]));
                        }
                        break;
                    case TypeCode.Int64:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(Convert.ToInt64(buffer[i]));
                        }
                        break;
                    case TypeCode.UInt64:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(Convert.ToUInt64(buffer[i]));
                        }
                        break;
                    case TypeCode.Single:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(Convert.ToSingle(buffer[i]));
                        }
                        break;
                    case TypeCode.Double:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(Convert.ToDouble(buffer[i]));
                        }
                        break;
                    case TypeCode.Decimal:
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            writer.Write(Convert.ToDecimal(buffer[i]));
                        }
                        break;
                    default:
                        throw new NotImplementedException($"未实现的目标数据类型{dataTypeCode.ToString()}");
                }
            }
        }

        /// <summary>
        /// 将指定类型指定长度的基础数据buffer写到BinaryWriter中
        /// </summary>
        /// <typeparam name="T">目标数据类型[SByte-Int16-UInt16-Int32-UInt32-Int64-UInt64-float-double-decimal]</typeparam>
        /// <param name="filePath">文件路径</param>
        /// <param name="buffer">包含要写入的数据数组</param>
        /// <param name="startIndex">要从buffer中读取且要写入流的第一个字节的索引,小于等于0从头开始</param>
        /// <param name="count">要从buffer中读取且要写入流的元素个数,小于等于0表示到结尾</param>
        /// <param name="fileMode">文件打开操作模式</param>
        /// <param name="dataTypeCode">写到BinaryWriter中的目标数据类型,为null时与buffer数据类型一致</param>
        public static void WriteBuffer<T>(string filePath, T[] buffer, int startIndex = -1, int count = -1,
            FileMode fileMode = FileMode.CreateNew, TypeCode? dataTypeCode = null)
            where T : struct, IConvertible, IFormattable, IComparable<T>, IEquatable<T>
        {
            if (string.IsNullOrWhiteSpace(filePath))
            {
                throw new ArgumentNullException(nameof(filePath));
            }
            else
            {
                DirectoryInfoEx.CheckFilePathDirectory(filePath);
            }

            if (buffer == null)
            {
                throw new ArgumentNullException(nameof(buffer));
            }

            using (var fs = new FileStream(filePath, fileMode, FileAccess.Write))
            {
                var writer = new BinaryWriter(fs);
                PrimitiveWriteBuffer<T>(writer, dataTypeCode, buffer, startIndex, count);
            }
        }

        /// <summary>
        /// 将指定类型指定长度的基础数据buffer写到BinaryWriter中
        /// </summary>
        /// <typeparam name="T">目标数据类型[SByte-Int16-UInt16-Int32-UInt32-Int64-UInt64-float-double-decimal]</typeparam>
        /// <param name="stream">目标数据流</param>
        /// <param name="buffer">包含要写入的数据数组</param>
        /// <param name="startIndex">要从buffer中读取且要写入流的第一个字节的索引,小于等于0从头开始</param>
        /// <param name="count">要从buffer中读取且要写入流的元素个数,小于等于0表示到结尾</param>
        /// <param name="dataTypeCode">写到BinaryWriter中的目标数据类型,为null时与buffer数据类型一致</param>
        public static void WriteBuffer<T>(Stream stream, T[] buffer, int startIndex = -1, int count = -1, TypeCode? dataTypeCode = null)
            where T : struct, IConvertible, IFormattable, IComparable<T>, IEquatable<T>
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            if (!stream.CanWrite)
            {
                throw new ArgumentException("数据流不可写", nameof(stream));
            }

            if (buffer == null)
            {
                throw new ArgumentNullException(nameof(buffer));
            }

            var writer = new BinaryWriter(stream);
            PrimitiveWriteBuffer<T>(writer, dataTypeCode, buffer, startIndex, count);
        }

        /// <summary>
        /// 将指定类型指定长度的基础数据buffer写到BinaryWriter中
        /// </summary>
        /// <typeparam name="T">目标数据类型[SByte-Int16-UInt16-Int32-UInt32-Int64-UInt64-float-double-decimal]</typeparam>
        /// <param name="writer">BinaryWriter</param>
        /// <param name="buffer">包含要写入的数据数组</param>
        /// <param name="startIndex">要从buffer中读取且要写入流的第一个字节的索引,小于等于0从头开始</param>
        /// <param name="count">要从buffer中读取且要写入流的元素个数,小于等于0表示到结尾</param>
        /// <param name="dataTypeCode">写到BinaryWriter中的目标数据类型,为null时与buffer数据类型一致</param>
        public static void WriteBuffer<T>(BinaryWriter writer, T[] buffer, int startIndex = -1, int count = -1, TypeCode? dataTypeCode = null)
            where T : struct, IConvertible, IFormattable, IComparable<T>, IEquatable<T>
        {
            if (writer == null)
            {
                throw new ArgumentNullException(nameof(writer));
            }

            if (!writer.BaseStream.CanWrite)
            {
                throw new ArgumentException("数据流不可写", nameof(writer));
            }

            if (buffer == null)
            {
                throw new ArgumentNullException(nameof(buffer));
            }

            PrimitiveWriteBuffer<T>(writer, dataTypeCode, buffer, startIndex, count);
        }

        #endregion

    }
}
